package com.grace.web.controller.server;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;

import org.apache.tika.Tika;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.grace.common.annotation.Log;
import com.grace.common.constant.HttpStatus;
import com.grace.common.core.controller.BaseController;
import com.grace.common.core.domain.AjaxResult;
import com.grace.common.core.page.TableDataInfo;
import com.grace.common.enums.BusinessType;
import com.grace.common.enums.GraceStorageRoot;
import com.grace.common.exception.file.FileSizeLimitExceededException;
import com.grace.common.exception.file.InvalidExtensionException;
import com.grace.common.utils.file.FileUtils;
import com.grace.oss.domain.OlyOss;
import com.grace.oss.factory.OssFactory;
import com.grace.oss.properties.OssConfigProperties;
import com.grace.oss.service.OssService;
import com.grace.system.service.impl.SysConfigServiceImpl;

/**
 * 文件存储Controller
 * 
 * @author zg
 * @date 2022-10-21
 */
@RestController
@RequestMapping("/server/oss")
public class OssServerController extends BaseController {
    @Autowired
    private OssService olyOssService;

    @Autowired
    private OssFactory ossHandler;

    @Autowired
    private SysConfigServiceImpl configService;

    private static final Logger log = LoggerFactory.getLogger(OssServerController.class);

    /**
     * 查询文件存储列表
     */
    @PreAuthorize("@ss.hasPermi('server:oss:list')")
    @GetMapping("/list")
    public TableDataInfo list(OlyOss olyOss) {
        startPage();
        List<OlyOss> list = olyOssService.selectOlyOssList(olyOss);
        return getDataTable(list);
    }

    /**
     * 获取文件存储详细信息
     */
    @PreAuthorize("@ss.hasPermi('server:oss:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(olyOssService.selectOlyOssById(id));
    }

    /**
     * 文件上传
     * 
     * @param file
     * @return
     * @throws IOException
     * @throws InvalidExtensionException
     * @throws FileSizeLimitExceededException
     */

    @PostMapping("/upload")
    @PreAuthorize("@ss.hasPermi('server:oss:upload')")
    public AjaxResult upload(MultipartFile file)
            throws IOException, FileSizeLimitExceededException, InvalidExtensionException {
        return success(ossHandler.get().ossUpload(file, GraceStorageRoot.UPLOAD_DIR));
    }

    /**
     * 批量文件上传
     * 
     * @param files
     * @return
     * @throws Exception
     */

    @PostMapping("/uploads")
    @PreAuthorize("@ss.hasPermi('server:oss:upload')")
    public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception {
        List<OlyOss> dates = new ArrayList<OlyOss>();
        for (MultipartFile file : files) {
            dates.add(ossHandler.get().ossUpload(file, GraceStorageRoot.UPLOAD_DIR));
        }
        return success(dates);
    }

    /**
     * 支持自定义返回参数
     * 
     * @param file 上传文件
     * @param code 自定义返回状态
     * @param url  自定义返回路径
     * @param msg  自定义返回消息
     * @return
     * @throws FileSizeLimitExceededException
     * @throws InvalidExtensionException
     * @throws IOException
     */
    @PostMapping("/upload/{code}/{url}/{msg}")
    @PreAuthorize("@ss.hasPermi('server:oss:upload')")
    public Map<String, Object> uploadResult(MultipartFile file, @PathVariable("code") String code,
            @PathVariable("url") String url, @PathVariable("msg") String msg)
            throws FileSizeLimitExceededException, InvalidExtensionException, IOException {
        OlyOss ossResult = ossHandler.get().ossUpload(file, GraceStorageRoot.UPLOAD_DIR);
        Map<String, Object> mm = new HashMap<>();
        mm.put(code, HttpStatus.SUCCESS);
        mm.put(url, ossResult.getDomain() + ossResult.getFk());
        mm.put(msg, "上传成功");
        return mm;
    }

    /**
     * 修改保存参数配置
     * 通过key批量保存
     * 默认设置为字符串类型
     * 
     * @param mp
     * @return
     */
    @PreAuthorize("@ss.hasPermi('server:oss:config')")
    @PostMapping("/updateConfig")
    @Log(title = "储存参数", businessType = BusinessType.UPDATE)
    public AjaxResult updateConfig(@RequestBody Map<String, Object> mp) {
        mp.put("configGroup", OssConfigProperties.OSS_CONFIG_GROUP.getValue());
        return toAjax(configService.updatesByMap(mp, getUsername()));
    }

    /**
     * 删除文件存储
     */
    @PreAuthorize("@ss.hasPermi('server:oss:remove')")
    @Log(title = "文件存储", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        int de = 0;
        for (int index = 0; index < ids.length; index++) {
            ossHandler.get().ossDelete(olyOssService.selectOlyOssById(ids[index]).getFk());
            de++;
        }
        return toAjax(de);
    }

    /**
     * 
     * @param f        文件夹
     * @param y        年
     * @param m        月
     * @param d        日
     * @param filename 文件名
     * @param response
     */
    @GetMapping("/download/{f}/{y}/{m}/{d}/{file:.+}")
    public void downloadFile(@PathVariable("f") String f, @PathVariable("y") String y, @PathVariable("m") String m,
            @PathVariable("d") String d, @PathVariable("file") String filename, HttpServletResponse response) {

        outputFile(Paths.get(GraceStorageRoot.UPLOAD_DIR.getWorkRoot(), f, y, m, d, filename).toString(), response);
    }

    /**
     * 
     * @param f        文件夹
     * @param y        年
     * @param m        月
     * @param d        日
     * @param filename 文件名
     * @param response
     */
    @GetMapping("/download/avatar/{f}/{y}/{m}/{d}/{file:.+}")
    public void downloadAvatar(@PathVariable("f") String f, @PathVariable("y") String y, @PathVariable("m") String m,
            @PathVariable("d") String d, @PathVariable("file") String filename, HttpServletResponse response) {

        outputFile(Paths.get(GraceStorageRoot.AVATAR_DIR.getWorkRoot(), f, y, m, d, filename).toString(), response);
    }

    // 输出文件流
    private void outputFile(String fileDir, HttpServletResponse response) {
        // 判断文件是否存在
        File inFile = new File(fileDir);
        PrintWriter writer = null;
        if (!inFile.exists() || !inFile.isFile()) {
            try {
                response.setContentType("text/html;charset=UTF-8");
                writer = response.getWriter();
                writer.write(
                        "<!doctype html><title>404 Not Found</title><h1 style=\"text-align: center\">404 Not Found</h1><hr/><p style=\"text-align: center\">Oss File Server</p>");
                writer.flush();
            } catch (IOException e) {
                log.error("下载文件失败", e);
            }
            return;
        }
        // 获取文件类型
        String contentType = "application/force-download";
        try {
            contentType = new Tika().detect(inFile);
        } catch (IOException e) {
            log.error("获取contentType失败", e.getMessage());
        }
        response.setContentType(contentType);
        try {
            FileUtils.setAttachmentResponseHeader(response, inFile.getName());
            FileUtils.writeBytes(fileDir, response.getOutputStream());
        } catch (IOException e) {
            log.error("下载文件失败", e);
        }

    }

}
